/******************************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Ltd.                       */
/*                                                                            */
/*  NAME      = sybase_common.c                                               */
/*  NOTE      = TDS 请求解析                                                  */
/*  DATE      = 2014/09/30 by zhengxd                                         */
/******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <stdint.h>
#include <limits.h>

#include "sybase_common.h"
#include "sybase_token.h"

#if defined(FRLINUX4) || defined(FRLINUX5)
#define ULLONG_MAX 18446744073709551615ULL
#endif

#define SYBASE_REPORT_KEY_DBNAME     APM_REPORT_KEY_SESSION".sybase.dbname"

/*******************************************************************************
*  FUNC     :  释放内存
*  ARGS     :  pp_buffer
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
void sybase_free(char **pp_buffer)
{
    if (pp_buffer == NULL || *pp_buffer == NULL)
    {
        return;
    }

    frfree(*pp_buffer);
    *pp_buffer = NULL;
    return;
}

/*******************************************************************************
*  FUNC     :  altfmt节点释放函数
*  ARGS     :  p_st_node (altfmt节点)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
void sybase_altfmt_node_free(Frlist_node *p_st_node)
{
    if( p_st_node == NULL || p_st_node->data == NULL)
    {
        return;
    }

    Sybase_altfmt *p_st_altfmt = (Sybase_altfmt *)p_st_node->data;
    frlist_destroy(p_st_altfmt->p_lst_data_type, frdb_metadata_node_free);
    frfree(p_st_altfmt);
    return;
}

/*******************************************************************************
*  FUNC     :  初始化分片包信息
*  ARGS     :  pp_st_fragment (分片包信息)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
void sybase_init_fragment(L7_fragment_sybase *p_st_fragment)
{
    if (p_st_fragment == NULL)
    {
        return;
    }

    if (p_st_fragment->p_st_data)
    {
        bytebuff_free(&p_st_fragment->p_st_data);
    }
    memset(p_st_fragment, 0x0, sizeof(L7_fragment_sybase));

    return;
}

/*******************************************************************************
*  FUNC     :  初始化分片包信息
*  ARGS     :  pp_st_fragment (分片包信息)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
void sybase_destroy_fragment(L7_fragment_sybase **pp_st_fragment)
{
    if (pp_st_fragment == NULL || *pp_st_fragment == NULL)
    {
        return;
    }

    L7_fragment_sybase *p_st_fragment = *pp_st_fragment;

    if (p_st_fragment->p_st_data)
    {
        bytebuff_free(&p_st_fragment->p_st_data);
    }

    frfree(p_st_fragment);
    *pp_st_fragment = NULL;
    return;
}

/*******************************************************************************
*  FUNC     :  做成request
*  ARGS     :  u8_packet_type(TDS的packet类型)
*  RTN      :  非NULL       (normal)
*              NULL         (error)
*  NOTE     :
*******************************************************************************/
L7_req_sybase* sybase_create_request(uint8_t u8_packet_type)
{
    L7_req_sybase *p_st_req = NULL;

    /* 申请request */
    p_st_req = (L7_req_sybase *)frmalloc(sizeof(L7_req_sybase));
    if (p_st_req == NULL)
    {
        return NULL;
    }
    /* 初始化 */
    memset(p_st_req, 0x0, sizeof(L7_req_sybase));
    /* 设置类型 */
    p_st_req->u8_packet_type = u8_packet_type;
    p_st_req->i_need_req_resp = FRTDS_DIRECT_REQUEST;

    return p_st_req;
}

/*******************************************************************************
*  FUNC     :  销毁session信息
*  ARGS     :  pp_st_sess(session信息)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
void sybase_destroy_session(L7session_sybase **pp_st_sess)
{
    if(pp_st_sess == NULL || *pp_st_sess == NULL)
    {
        return;
    }

    L7session_sybase *p_st_sess = *pp_st_sess;

    if (p_st_sess->p_cli_host_user)
    {
        frfree(p_st_sess->p_cli_host_user);
    }
    if (p_st_sess->p_program)
    {
        frfree(p_st_sess->p_program);
    }
    if (p_st_sess->p_db_name)
    {
        frfree(p_st_sess->p_db_name);
    }
    if (p_st_sess->p_db_user)
    {
        frfree(p_st_sess->p_db_user);
    }
    if (p_st_sess->p_tds_charset)
    {
        frfree(p_st_sess->p_tds_charset);
    }

    frfree(p_st_sess);
    *pp_st_sess = NULL;
    return;
}

/*******************************************************************************
*  FUNC     :  request信息初始化
*  ARGS     :  pp_st_request(request信息)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
void sybase_int_request(L7_req_sybase *p_st_req)
{
    uint8_t u8_packet_type = 0;

    if(p_st_req == NULL )
    {
        return;
    }

    u8_packet_type = p_st_req->u8_packet_type;
    if (p_st_req->p_sql)
    {
        frfree(p_st_req->p_sql);
    }
    frlist_remove_all(&p_st_req->st_metadata_tmp, frdb_metadata_node_free);
    frlist_remove_all(&p_st_req->st_metadata_bind, frdb_metadata_node_free);
    if (p_st_req->i_new_statement == FR_YES)
    {
        /* 释放SQL statement信息 */
        frdb_statement_free(&(p_st_req->p_st_statement));
    }
    memset(p_st_req, 0x0, sizeof(L7_req_sybase));

    /* 设置类型 */
    p_st_req->u8_packet_type = u8_packet_type;
    p_st_req->i_need_req_resp = FRTDS_DIRECT_REQUEST;
    return;
}

/*******************************************************************************
*  FUNC     :  request信息释放
*  ARGS     :  pp_st_req(request信息)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
void sybase_destroy_request(L7_req_sybase **pp_st_req)
{
    if(pp_st_req == NULL || *pp_st_req == NULL)
    {
        return;
    }

    L7_req_sybase *p_st_req = *pp_st_req;

    if (p_st_req->p_sql)
    {
        frfree(p_st_req->p_sql);
    }
    frlist_remove_all(&p_st_req->st_metadata_tmp, frdb_metadata_node_free);
    frlist_remove_all(&p_st_req->st_metadata_bind, frdb_metadata_node_free);
    if (p_st_req->i_new_statement == FR_YES)
    {
        /* 释放SQL statement信息 */
        frdb_statement_free(&(p_st_req->p_st_statement));
    }

    frfree(p_st_req);
    *pp_st_req = NULL;
    return;
}

/*******************************************************************************
*  FUNC     :  response信息释放
*  ARGS     :  pp_st_request(request信息)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
void sybase_int_response(L7_resp_sybase *p_st_resp)
{
    if(p_st_resp == NULL)
    {
        return;
    }

    if (p_st_resp->p_error_msg)
    {
        frfree(p_st_resp->p_error_msg);
    }
    frlist_remove_all(&p_st_resp->st_metadata_param, frdb_metadata_node_free);
    frlist_remove_all(&p_st_resp->st_metadata_column, frdb_metadata_node_free);
    frlist_remove_all(&p_st_resp->st_altfmt, sybase_altfmt_node_free);
    memset(p_st_resp, 0x0, sizeof(L7_resp_sybase));

    return;
}

/*******************************************************************************
*  FUNC     :  response信息释放
*  ARGS     :  pp_st_request(request信息)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
void sybase_destroy_response(L7_resp_sybase **pp_st_resp)
{
    if(pp_st_resp == NULL || *pp_st_resp == NULL)
    {
        return;
    }

    L7_resp_sybase *p_st_resp = *pp_st_resp;

    if (p_st_resp->p_error_msg)
    {
        frfree(p_st_resp->p_error_msg);
    }
    frlist_remove_all(&p_st_resp->st_metadata_param, frdb_metadata_node_free);
    frlist_remove_all(&p_st_resp->st_metadata_column, frdb_metadata_node_free);
    frlist_remove_all(&p_st_resp->st_altfmt, sybase_altfmt_node_free);

    frfree(p_st_resp);
    *pp_st_resp = NULL;
    return;
}

/*******************************************************************************
*  FUNC     :  初始化私有SQL Server session
*  ARGS     :  p_st_private(私有session数据)
*  RTN      :  FR_SUCC       (normal)
*              FR_FAIL       (error)
*  NOTE     :  p_st_private必须不是NULL
*******************************************************************************/
void sybase_destroy_curr_info(L7session_sybase_private *p_st_private)
{
    if (p_st_private->p_st_req)
    {
        sybase_destroy_request(&p_st_private->p_st_req);
    }
    if (p_st_private->p_st_resp)
    {
        sybase_destroy_response(&p_st_private->p_st_resp);
    }
    sybase_init_fragment(p_st_private->p_st_fragment);

    return;
}

/*******************************************************************************
*  FUNC     :  根据session创建session data列表
*  ARGS     :  p_st_conn (CT信息)
*           :  p_st_session (sybase session信息)
*  RTN      :  APM_L7_ANALYZE_SUCC  (success)
*              APM_L7_ANALYZE_FAIL  (failed)
*  NOTE     :  p_st_session必须不为NULL
*******************************************************************************/
Frreport_body_data* sybase_new_report_body(Conntrack *p_st_conn
                                           , L7session_sybase *p_st_sess)
{
    int i_ret = FR_SUCC;
    Frreport_body_data *p_st_sess_body = NULL;

    /* 创建report body */
    p_st_sess_body = frreport_body_new_l7(p_st_conn);
    if (p_st_sess_body == NULL)
    {
        return NULL;
    }
    /* 追加connection相关信息 */
    i_ret = frreport_body_l7_add_connInfo(p_st_sess_body, p_st_conn);
    if (i_ret != FR_SUCC)
    {
        frreport_body_free(&p_st_sess_body);
        return NULL;
    }

    /* add server */
    if (p_st_sess->p_program)
    {
        i_ret = frreport_body_l7_add_str(p_st_sess_body
                                         , APM_REPORT_KEY_SESSION_SERVER
                                         , p_st_sess->p_program);
        if (i_ret != FR_SUCC)
        {
            frreport_body_free(&p_st_sess_body);
            return NULL;
        }
    }
    /* add username */
    if (p_st_sess->p_db_user)
    {
        i_ret = frreport_body_l7_add_str(p_st_sess_body
                                         , APM_REPORT_KEY_SESSION_USERNAME
                                         , p_st_sess->p_db_user);
        if (i_ret != FR_SUCC)
        {
            frreport_body_free(&p_st_sess_body);
            return NULL;
        }
    }
    /* add dbname */
    if (p_st_sess->p_db_name)
    {
        i_ret = frreport_body_l7_add_str(p_st_sess_body
                                         , SYBASE_REPORT_KEY_DBNAME
                                         , p_st_sess->p_db_name);
        if (i_ret != FR_SUCC)
        {
            frreport_body_free(&p_st_sess_body);
            return NULL;
        }
    }
    if (p_st_sess->st_login.tv_sec != 0
        || p_st_sess->st_login.tv_usec != 0)
    {
        /* add request start time */
        i_ret = frreport_body_l7_add_timeval(p_st_sess_body
                                            , APM_REPORT_KEY_SESSION_LOGIN_TIMESTAMP
                                            , &p_st_sess->st_login);
        if (i_ret != FR_SUCC)
        {
            frreport_body_free(&p_st_sess_body);
            return NULL;
        }
    }

    return p_st_sess_body;
}

/*******************************************************************************
*  FUNC     :  追加statement到hash中
*  ARGS     :  p_st_private (私有数据)
*           :  i_cursor_dynamic (cursor or dynamic)
*           :  i_req_resp (request or response)
*  RTN      :  APM_L7_ANALYZE_SUCC
*              APM_L7_ANALYZE_FAIL
*  NOTE     :  p_st_private肯定不为NULL
*******************************************************************************/
int sybase_add_statement(L7session_sybase_private *p_st_private
                         , int i_cursor_dynamic
                         , int i_req_resp)
{
    int i_ret = APM_L7_ANALYZE_SUCC;
    long l_cursor_id = 0;
    char *p_cursor_name = NULL;
    Frlist_node *p_st_node = NULL;
    L7_req_sybase *p_st_req = p_st_private->p_st_req;
    L7_resp_sybase *p_st_resp = p_st_private->p_st_resp;

    /* 创建hash节点 */
    p_st_node = frlist_node_create(p_st_req->p_st_statement);
    if (p_st_node == NULL)
    {
        return APM_L7_ANALYZE_FAIL;
    }

    if (i_req_resp == FRTDS_DIRECT_REQUEST)
    {
        if (p_st_req == NULL)
        {
            return APM_L7_ANALYZE_FAIL;
        }
        l_cursor_id = p_st_req->l_cursor_id;
        p_cursor_name = p_st_req->arr_cursor_name;
    }
    else if (i_req_resp == FRTDS_DIRECT_RESPONSE)
    {
        if (p_st_resp == NULL)
        {
            return APM_L7_ANALYZE_FAIL;
        }
        l_cursor_id = p_st_resp->l_cursor_id;
        p_cursor_name = p_st_resp->arr_cursor_name;
    }
    else
    {
        return APM_L7_ANALYZE_FAIL;
    }

    /* 处理cursor信息 */
    if (i_cursor_dynamic == SYBASE_CURSOR)
    {
        /* find statement for hash */
        if (l_cursor_id)
        {
            /* 删除原有的 */
            frhash2_delLong(p_st_private->p_hash_prepare
                           , l_cursor_id
                           , frdb_statement_node_free);
            /* 追加现有的 */
            p_st_req->p_st_statement->st_metadata_column = p_st_resp->st_metadata_column;
            memset(&p_st_resp->st_metadata_column, 0x0, sizeof(p_st_resp->st_metadata_column));
            i_ret = frhash2_addLong(p_st_private->p_hash_prepare
                                   , l_cursor_id, p_st_node);
        }
        else
        {
            /* 删除原有的 */
            frhash2_delStr(p_st_private->p_hash_prepare
                           , p_cursor_name
                           , strlen(p_cursor_name)
                           , frdb_statement_node_free);
            /* 追加现有的 */
            i_ret = frhash2_addStr(p_st_private->p_hash_prepare
                                  , p_cursor_name
                                  , strlen(p_cursor_name)
                                  , p_st_node);
        }
    }
    else /* 处理dynamic */
    {
        /* 删除原有的 */
        frhash2_delStr(p_st_private->p_hash_prepare, p_st_req->arr_id
                       , strlen(p_st_req->arr_id), frdb_statement_node_free);
        /* 追加现有的 */
        i_ret = frhash2_addStr(p_st_private->p_hash_prepare, p_st_req->arr_id
                              , strlen(p_st_req->arr_id), p_st_node);
    }
    /* add failed */
    if (i_ret != FR_SUCC)
    {
        frfree(p_st_node);
        return APM_L7_ANALYZE_FAIL;
    }

    /* 出力设置 */
    p_st_req->i_new_statement = FR_NO;
    return APM_L7_ANALYZE_SUCC;
}

/*******************************************************************************
*  FUNC     :  判断sql语句是否是select
*  ARGS     :  p_sql (sql语句)
*  RTN      :  1       (true)
*              0       (false)
*  NOTE     :
*******************************************************************************/
int sybsae_select_chk(const char *p_sql)
{
    if (p_sql == NULL)
    {
        return FR_NO;
    }

    /* 跳过字符串开头的空白字符 */
    while (*p_sql)
    {
        if (*p_sql == ' ' || *p_sql == '\t' || *p_sql == '\r' || *p_sql == '\n')
        {
            p_sql++;
            continue;
        }
        else
        {
            break;
        }
    }

    /* 判断是否是select, 不区分大小写 */
    if (strncmp(p_sql, "select", 6))
    {
        return FR_NO;
    }

    /* select之后必须有一个空白字符 */
    p_sql += 6;
    if (*p_sql == ' ' || *p_sql == '\t' || *p_sql == '\r' || *p_sql == '\n')
    {
        return FR_YES;
    }
    else
    {
        return FR_NO;
    }
}

